home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / vtkerma2.arc / MSXMODEM.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-02-13  |  21.8 KB  |  870 lines

  1.     PAGE 59, 132
  2.  
  3.     TITLE MSXModem -- Send and receive files using the XMODEM protocol
  4.  
  5. ; Update 8 Jan 86
  6.  
  7. IF1
  8.  %OUT >> Starting pass 1
  9. ELSE
  10.  %OUT >> Starting pass 2
  11. ENDIF
  12.  
  13.     PUBLIC XSend, XReceive
  14.  
  15.     INCLUDE MsDefs.H
  16.  
  17. DataS    SEGMENT PUBLIC 'DataS'
  18.  
  19.     EXTRN Count:WORD, Pack:BYTE, OFilSz:WORD, TFilSz:WORD, PortVal:WORD
  20.  
  21. ; Static data
  22.  
  23. ErMs31    DB '? File not found',cr,lf,'$'
  24. ErMs32    DB "? Can't create file",cr,lf,'$'
  25. No_data_in_file DB '? File is empty', Cr, Lf, '$'
  26. No_initiating_NAK DB 'Timeout waiting for receiver to start$'
  27. Too_many_retries DB 'Too many retries$'
  28. XM_send_status    DB cr,'         XMODEM send: Waiting for receiver to start$'
  29. XM_receive_status DB cr,'      XMODEM receive: Starting$'
  30. In_progress DB 'In progress$'
  31. Completed DB 'Completed$'
  32. Failed    DB 'Failed$'
  33. File_help DB ' File specification with optional path name$'
  34.  
  35. ; Writable data
  36.  
  37.     EVEN
  38. Tally    DW 0            ; Counter for checksum
  39. Filename_ptr DW 0        ; Pointer to filename from SPath routine
  40. Handle    DW 0            ; File handle for FT file
  41. File_size DD 0            ; File size
  42. Buffer_ptr DW 0            ; Pointer into file buffer
  43. Buffer_count DW 0        ; Count of characters in buffer
  44. HrMn    DW 0            ; Place to save hours and minutes
  45. ScHn    DW 0            ; Place to save seconds and hundredths
  46. TFile    DB 100 DUP (?)        ; Place to store file name
  47. Buffer    DB 1024 DUP (?)        ; File I/O buffer
  48. Abort_flag DB 0            ; Flag that ^C was hit
  49. EOT_flag DB 0            ; Flag that we received a valid EOT signal
  50. Timeout DB 0            ; Number of seconds to allow
  51.  
  52. DataS    ENDS
  53.  
  54. Code    SEGMENT PUBLIC
  55.  
  56.     EXTRN Comnd:NEAR, SPath:NEAR, Init:NEAR, Close_transfer_screen:NEAR
  57.     EXTRN Show_error:NEAR, Show_retries:NEAR, Show_status:NEAR, PerPr:NEAR
  58.     EXTRN SerIni:NEAR, Nout:NEAR, RRInit:NEAR, Init:NEAR, Show_packets:NEAR
  59.     EXTRN ClrFln:NEAR, Write_to_standard_output:NEAR, KbPr:NEAR, PrtChr:NEAR
  60.     EXTRN Beep:NEAR, Say_aborted:NEAR, OutChr:NEAR, ClrBuf:NEAR, SerRst:NEAR
  61.     EXTRN EOT_bells:NEAR
  62.  
  63.     ASSUME cs:Code, ds:DataS, es:DataS
  64.  
  65.  
  66. ; XReceive -- XMODEM receive routine, called at command level
  67.  
  68. XReceive PROC
  69.  
  70.     mov ah, CMTXT        ; Read in a line of text
  71.     mov bx, OFFSET TFile    ; Temp area for text, max 100 chars
  72.     mov dx, OFFSET File_help ; File specification with optional path name
  73.     call Comnd        ; Do it
  74.      jmp RSkp
  75.  
  76.     mov si, OFFSET TFile    ; Point to start of user input
  77.     mov bl, ah        ; Copy length to bl
  78.     sub bh, bh        ; Clear high half
  79.     mov BYTE PTR [si+bx], 0    ; Make it ASCIZ
  80.  
  81.     mov ax, (CREATE2*256) + 0 ; DOS 2.0 file create call
  82.     sub cx, cx        ; No special attributes
  83.     mov dx, OFFSET TFile    ; Point to name again
  84.     int Dos
  85.      jnc XRE_3        ;  Create ok, keep going
  86.  
  87. XRE_2:    mov ah, PrStr        ; Code to type a message
  88.     mov dx, OFFSET ErMs32    ; ? Can't create file
  89.     int Dos            ; Type it
  90.  
  91.     jmp RSkp
  92.  
  93. XRE_3:    mov Buffer_count, 0    ; Clear count of chars in buffer
  94.     mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
  95.  
  96.     mov Handle, ax        ; Save file descriptor
  97.     mov OFilSz, 0        ; Flag no percentages on this
  98.  
  99.     call SerRst        ; Unhook serial interrupt first just-in-case
  100.     call SerIni        ; Set up serial port as required
  101.  
  102.     call RRInit        ; Set up counters
  103.     call Init        ; Set up screen for file transfer
  104.  
  105.     mov dx, OFFSET XM_receive_status ; "XMODEM receive: Starting"
  106.     call Show_status    ; Display status
  107.  
  108.     mov Pack.NumRtr, 0    ; Clear the retry count
  109.     call Show_retries    ;  then display it
  110.  
  111.     call ClrFln        ; Clear filename and position us there
  112.     mov dx, OFFSET TFile    ; Give him the filename pointer
  113.     call Write_to_standard_output ; Use common routine to type filename
  114.  
  115.     mov bx, PortVal        ; Port structure
  116.     mov al, [bx].floflg    ; Save current flow control setting
  117.     push ax
  118.     mov [bx].floflg, 0    ; Turn it off for XMODEM
  119.  
  120.     call Do_XMODEM_receive    ; Use other routine to do the work
  121.  
  122.     call EOT_bells        ; Make an optional noise
  123.  
  124.     mov bx, PortVal        ; Port structure
  125.     pop ax
  126.     mov [bx].floflg, al    ; Restore it to what it was
  127.  
  128.     call Close_transfer_screen ; Make screen go normal again
  129.  
  130.     mov ah, CLOSE2        ; Code to close a file
  131.     mov bx, Handle        ; The file handle
  132.     int Dos            ; Close the file
  133.  
  134.     cmp Abort_flag, 0    ; Did we abort this transfer?
  135.      je XRE_9        ;  No
  136.  
  137.     mov ah, 41h        ; Code to unlink (delete) a file
  138.     mov dx, OFFSET TFile    ; Filename used to create file
  139.     int Dos            ; Delete the file
  140.  
  141.     PUBLIC XRE_9
  142.  
  143. XRE_9:    jmp RSkp        ; Done here
  144.  
  145. XReceive ENDP
  146.  
  147.  
  148. ; XSend -- XMODEM send routine, called at command level
  149.  
  150. XSend    PROC
  151.  
  152.     mov ah, CMTXT        ; Read in a line of text
  153.     mov bx, OFFSET TFile    ; Temp area for text, max 100 chars
  154.     mov dx, OFFSET File_help ; File specification with optional path name
  155.     call Comnd        ; Do it
  156.      jmp RSkp
  157.  
  158.     mov si, OFFSET TFile    ; Point to start of user input
  159.     mov bl, ah        ; Copy length to bl
  160.     sub bh, bh        ; Clear high half
  161.     mov BYTE PTR [si+bx], 0    ; Make it ASCIZ
  162.  
  163.     mov ax, si        ; Point to name again
  164.     call SPath        ; Is it around?
  165.      jc XSE_2        ;  No, go complain
  166.  
  167.     mov Filename_ptr, ax    ; Save pointer to filename for later
  168.     mov dx, ax        ; Point to name from SPath
  169.     mov ax, (Open2*256) + 0    ; DOS 2.0 open call for read
  170.     int Dos
  171.      jnc XSE_3        ; Open ok, keep going
  172.  
  173. XSE_2:    mov ah, PrStr        ; Code to type a message
  174.     mov dx, OFFSET ErMs31    ; ? File not found
  175.     int Dos            ; Type it
  176.  
  177.     jmp RSkp
  178.  
  179. XSE_3:    mov Handle, ax        ; Save file descriptor
  180.     mov bx, ax        ; Need descriptor here
  181.  
  182.     mov ax, (LSeek*256) + 2    ; Seek 0 bytes from end
  183.     sub cx, cx
  184.     sub dx, dx
  185.     int Dos
  186.  
  187.     mov WORD PTR File_size, ax ; Store length
  188.     mov WORD PTR File_size + 2, dx ;  (doubleword)
  189.  
  190.     mov cx, ax        ; Copy low order part to cx
  191.     or cx, dx        ; Merge the two words
  192.      jnz XSE_4        ;  There is at least one character
  193.  
  194.     mov ah, PrStr        ; Code to type a message
  195.     mov dx, OFFSET No_data_in_file ; ? File is empty
  196.     int Dos            ; Type the message
  197.  
  198.     jmp RSkp        ; Give up
  199.  
  200. XSE_4:    mov bx, 100        ; Get a 100 into bx
  201.     div bx            ; Convert file size for percentage calculation
  202.     mov OFilSz, ax        ; Save it for PerPr
  203.  
  204.     mov ax, (LSeek*256) + 0    ; Seek back to the beginning
  205.     mov bx, Handle        ; Get back the file handle
  206.     sub cx, cx
  207.     sub dx, dx
  208.     int Dos
  209.  
  210.     call Read_a_bufferfull    ; Use other routine to load the buffer
  211.  
  212.     call SerRst        ; Unhook serial interrupt first just-in-case
  213.     call SerIni        ; Set up serial port as required
  214.  
  215.     call RRInit        ; Set up counters
  216.     call Init        ; Set up screen for file transfer
  217.  
  218.     mov dx, OFFSET XM_send_status ; "XMODEM send: Waiting for ..."
  219.     call Show_status    ; Display status
  220.  
  221.     mov Pack.NumRtr, 0    ; Clear the retry count
  222.     call Show_retries    ;  then display it
  223.  
  224.     call ClrFln        ; Clear filename and position us there
  225.     mov dx, Filename_ptr    ; Give him the filename pointer
  226.     call Write_to_standard_output ; Use common routine to type filename
  227.  
  228.     mov bx, PortVal        ; Port structure
  229.     mov al, [bx].floflg    ; Save current flow control setting
  230.     push ax
  231.     mov [bx].floflg, 0    ; Turn it off for XMODEM
  232.  
  233.     call Do_XMODEM_send    ; Use other routine to do the work
  234.  
  235.     call EOT_bells        ; Make an optional noise
  236.  
  237.     mov bx, PortVal        ; Port structure
  238.     pop ax
  239.     mov [bx].floflg, al    ; Restore it to what it was
  240.  
  241.     call Close_transfer_screen ; Make screen go normal again
  242.  
  243.     mov ah, CLOSE2        ; Code to close a file
  244.     mov bx, Handle        ; The file handle
  245.     int Dos            ; Close the file
  246.  
  247.     jmp RSkp        ; Done here
  248.  
  249. XSend    ENDP
  250.  
  251.  
  252.     PUBLIC Write_a_bufferfull
  253.  
  254. ; Write_a_bufferfull -- Write to HANDLE from BUFFER
  255.  
  256. Write_a_bufferfull PROC
  257.  
  258.     cmp Buffer_count, 0    ; Are chars to dump?
  259.      jz WAB_1        ;  Nothing to do, just exit
  260.  
  261.     mov ah, WRITEF2        ; DOS 2.0 file handle write
  262.     mov bx, Handle        ; File handle to use
  263.     mov cx, Buffer_count    ; Amount of stuff in buffer
  264.     mov dx, OFFSET Buffer    ; Ptr to buffer
  265.     int Dos            ; Write a buffer full
  266.  
  267.     mov Buffer_count, 0    ; Clear count of chars in buffer
  268.  
  269. WAB_1:    mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
  270.     ret            ; Done here
  271.  
  272. Write_a_bufferfull ENDP
  273.  
  274.  
  275. ; Read_a_bufferfull -- Read from HANDLE into BUFFER
  276.  
  277. Read_a_bufferfull PROC
  278.  
  279.     mov si, OFFSET Buffer    ; Ptr to start of buffer
  280.     mov di, OFFSET Buffer + 1 ; Next byte
  281.     mov cx, (SIZE Buffer)-1    ; How many to copy
  282.     mov BYTE PTR [si], CtlZ    ; Clear first element of array with control-Z
  283.     rep movsb        ; Clear rest of array
  284.  
  285.     mov ah, ReadF2        ; DOS 2.0 file handle read
  286.     mov bx, Handle        ; File handle to use
  287.     mov cx, SIZE Buffer    ; Size of buffer
  288.     mov dx, OFFSET Buffer    ; Ptr to buffer
  289.     int Dos            ; Read a buffer full, or whatever we can get
  290.  
  291.     mov Buffer_count, ax    ; Store number of chars read
  292.     sub WORD PTR File_size, ax ; Account for what we have just read
  293.     sbb WORD PTR File_size + 2, 0 ; Do high order half also
  294.     mov Buffer_ptr, OFFSET Buffer ; Set up initial buffer pointer
  295.     ret            ; Done here
  296.  
  297. Read_a_bufferfull ENDP
  298.  
  299.  
  300. ; Do_XMODEM_receive -- Worker XMODEM file receive routine
  301.  
  302. Do_XMODEM_receive PROC
  303.  
  304.     call ClrBuf        ; Flush any chars already received
  305.  
  306.     mov EOT_flag, 0        ; Clear this flag
  307.     mov Pack.NumPkt, 0    ; Clear count of transmitted packets
  308.     mov Pack.PktNum, 1    ; XMODEM starts with packet number 1
  309.     mov TFilSz, 0        ; Clear out transfered file size ...
  310.     mov TFilSz + 2, 0    ;  ... low half too (this is backwards)
  311.  
  312.     mov ah, ASCII_NAK    ; Load up the char to send
  313.     call OutChr        ; Send it once
  314.      nop
  315.      nop
  316.      nop
  317.  
  318. DXR_1:    mov Pack.NumTry, 0    ; Clear this counter
  319.     mov dx, OFFSET In_progress ; "XMODEM receive: In progress"
  320.     call Show_status    ; Display status
  321.  
  322. DXR_2:    call Receive_a_packet    ; Receive a packet
  323.      jnc DXR_4        ;  Got a packet with no timeout or error
  324.  
  325.     cmp Abort_flag, 0    ; Aborted?
  326.      jz DXR_No_abort    ;  No
  327.  
  328.     mov dx, OFFSET Failed    ; Say transfer bombed
  329.     jmp Show_status
  330.  
  331. DXR_No_abort:
  332.     inc Pack.NumRtr        ; Bump global count
  333.     call Show_retries    ; Show the user
  334.  
  335.     inc Pack.NumTry        ; Bump the count of retries on this packet
  336.     cmp Pack.NumTry, 10    ; Hit 10 failures yet?
  337.      jl DXR_2        ;  No, keep going
  338.  
  339.     mov dx, OFFSET Failed
  340.     call Show_status
  341.  
  342.     mov dx, OFFSET Too_many_retries ; Too many retries
  343.     jmp Show_error        ; Complain on-screen, ret from there
  344.  
  345. DXR_4:    cmp EOT_flag, 0        ; Receive an EOT?
  346.      jne DXR_EOT        ;  Yes, ACK it and close file
  347.  
  348.     mov Pack.NumTry, 0    ; Clear per-packet error counter
  349.     inc Pack.PktNum        ; Advance to next packet number
  350.     inc Pack.NumPkt        ; Bump the number of packets
  351.     call Show_packets    ; Display the number of packets
  352.  
  353.     add TFilSz + 2, 128    ; Bump amount transmitted
  354.     adc TFilSz, 0        ;  and high half (done wrong for compatibility)
  355.  
  356.     call KbPr        ; Show how we're doing ...
  357.  
  358.     add Buffer_ptr, 128    ; Advance this ptr
  359.     add Buffer_count, 128    ; This counter too
  360.  
  361.     cmp Buffer_count, SIZE Buffer ; Is the buffer now full?
  362.      jl DXR_2        ;  Still room, get another packet
  363.  
  364.  
  365.  %OUT >> About half way through source file
  366.  
  367.  
  368.     call Write_a_bufferfull    ; Dump out the buffer
  369.     jmp DXR_2        ; Go do another packet
  370.  
  371. DXR_EOT:
  372.     call Write_a_bufferfull    ; Dump out the buffer
  373.     mov dx, OFFSET Completed ; "XMODEM receive: Completed"
  374.     jmp Show_status        ; Display status and go home
  375.  
  376. Do_XMODEM_receive ENDP
  377.  
  378.  
  379. ; Do_XMODEM_send -- Worker XMODEM file send routine
  380.  
  381. Do_XMODEM_send PROC
  382.  
  383.     call ClrBuf        ; Flush any chars already received
  384.  
  385.     mov Pack.NumPkt, 0    ; Clear count of transmitted packets
  386.     mov Pack.PktNum, 1    ; XMODEM starts with packet number 1
  387.     mov TFilSz, 0        ; Clear out transfered file size ...
  388.     mov TFilSz + 2, 0    ;  ... low half too (this is backwards)
  389.     call Wait_for_NAK    ; Give receiver time to start up and NAK us
  390.      jnc DXS_1        ;  We are OK
  391.  
  392.     ret            ; We never got one
  393.  
  394. DXS_1:    mov Pack.NumTry, 0    ; Clear this counter
  395.     mov dx, OFFSET In_progress ; "XMODEM send: In progress"
  396.     call Show_status    ; Display status
  397.  
  398. DXS_2:    call Send_a_packet    ; Send a packet
  399.     call Wait_for_ACK    ; Get an ACK if we can, fail on timeout or NAK
  400.      jnc DXS_4        ;  Got our ACK, move on ...
  401.  
  402.     cmp Abort_flag, 0    ; Aborted?
  403.      jz DXS_No_abort    ;  No
  404.  
  405.     mov dx, OFFSET Failed    ; Say transfer bombed
  406.     jmp Show_status
  407.  
  408. DXS_No_abort:
  409.     inc Pack.NumRtr        ; Bump global count
  410.     call Show_retries    ; Show the user
  411.  
  412.     inc Pack.NumTry        ; Bump the count of retries on this packet
  413.     cmp Pack.NumTry, 10    ; Hit 10 failures yet?
  414.      jl DXS_2        ;  No, keep going
  415.  
  416.     mov dx, OFFSET Failed
  417.     call Show_status
  418.  
  419.     mov dx, OFFSET Too_many_retries ; Too many retries
  420.     jmp Show_error        ; Complain on-screen, ret from there
  421.  
  422. DXS_4:    add Buffer_ptr, 128    ; Advance this ptr
  423.     sub Buffer_count, 128    ; Drop this counter
  424.  
  425.     mov Pack.NumTry, 0    ; Clear per-packet error counter
  426.     inc Pack.PktNum        ; Advance to next packet number
  427.     inc Pack.NumPkt        ; Bump the number of packets
  428.     call Show_packets    ; Display the number of packets
  429.  
  430.     add TFilSz + 2, 128    ; Bump amount transmitted
  431.     adc TFilSz, 0        ;  and high half (done wrong for compatibility)
  432.  
  433.     call KbPr        ; Show how we're doing ...
  434.     call PerPr        ; Percentage-wise also
  435.  
  436.     cmp Buffer_count, 0    ; Is the buffer now empty?
  437.      jg DXS_2        ;  Not empty, do more data
  438.      jl DXS_Send_EOT    ;  "Over-empty", Buffer_count wasn't 1024
  439.                 ;   this go round and we used them all up,
  440.                 ;   so this must be end-of-file
  441.  
  442.     mov ax, WORD PTR File_size ; Pick up half of file size
  443.     or ax, WORD PTR File_size + 2 ; Merge in other half
  444.      jz DXS_Send_EOT    ;  No chars to read, close it out
  445.  
  446.     call Read_a_bufferfull    ; Load up the buffer
  447.     jmp DXS_2        ; Go do another packet
  448.  
  449. DXS_Send_EOT:
  450.     mov Pack.NumTry, 0    ; Clear per-packet retry counter
  451.  
  452. DXS_EOT_loop:
  453.     mov ah, EOT        ; Get an ACK
  454.     call OutChr        ; Send it out
  455.      nop
  456.      nop
  457.      nop
  458.  
  459.     call Wait_for_ACK    ; Wait for ACK, NAK or timeout
  460.      jnc DXS_EOT_1        ;  Got our ACK, move on ...
  461.  
  462.     cmp Abort_flag, 0    ; Aborted?
  463.      jz DXS_EOT_no_abort
  464.  
  465.     mov dx, OFFSET Failed    ; Say transfer bombed
  466.     jmp Show_status
  467.  
  468. DXS_EOT_no_abort:
  469.     inc Pack.NumRtr        ; Bump global count
  470.     call Show_retries    ; Show the user
  471.  
  472.     inc Pack.NumTry        ; Bump the count of retries on this packet
  473.     cmp Pack.NumTry, 10    ; Hit 10 failures yet?
  474.      jl DXS_EOT_loop    ;  No, keep going
  475.  
  476.     mov dx, OFFSET Failed
  477.     call Show_status
  478.  
  479.     mov dx, OFFSET Too_many_retries ; Message
  480.     jmp Show_error        ; Complain on-screen, ret from there
  481.  
  482. DXS_EOT_1:
  483.     mov dx, OFFSET Completed ; "XMODEM send: Completed"
  484.     jmp Show_status        ; Display status
  485.  
  486. Do_XMODEM_send ENDP
  487.  
  488.  
  489. Wait_for_NAK PROC
  490.  
  491.     mov Abort_flag, 0    ; Clear abort flag
  492.     mov ah, 2Ch        ; Code to Get Time
  493.     int Dos            ; Get it
  494.  
  495.     inc cl            ; Bump the minutes
  496.     cmp cl, 59        ; Too many?
  497.      jbe WFN_doit        ;  No
  498.  
  499.     sub cl, 60        ; Pull down the minutes
  500.     inc ch            ; Bump the hours
  501.  
  502. WFN_doit:
  503.     mov HrMn, cx        ; Save hours and minutes
  504.     mov ScHn, dx        ; Save seconds and hundredths
  505.  
  506. WFN_Loop:
  507.     cmp Count, 0        ; Any characters to read?
  508.      jnz WFN_Got_char    ;  Found one
  509.  
  510.     mov dl, 0FFh        ; Want input mode
  511.     mov ah, DConIO        ; Code for direct console input w/o echo
  512.     int Dos            ; Get a char if any is there
  513.      jz WFN_No_keyboard    ;  User hasn't typed anything
  514.  
  515.     cmp al, 3        ; User type ^C?
  516.      jne WFN_Not_Ctrl_C    ;  No
  517.  
  518.     mov Abort_flag, 0FFh    ; Flag the abort
  519.     jmp Say_Aborted        ; Standard exit message for ^C
  520.  
  521. WFN_Not_Ctrl_C:
  522.     or al, al        ; Zero?
  523.      jne WFN_Beep        ;  No
  524.  
  525.     int Dos            ; Eat the second part of the funny char
  526.  
  527. WFN_Beep:
  528.     call Beep        ; User hit wrong key, make a noise
  529.  
  530. WFN_No_keyboard:
  531.     call Carry_if_expired    ; See if time has hit yet
  532.      jnc WFN_loop        ;  Not yet
  533.  
  534.     mov dx, OFFSET Failed
  535.     call Show_status
  536.  
  537.     mov dx, OFFSET No_initiating_NAK
  538.     jmp Show_error        ; Timeout, complain and return with carry on
  539.  
  540. WFN_Got_char:
  541.     call PrtChr        ; Pick up the character
  542.     cmp al, ASCII_NAK    ; Did we get what we wanted?
  543.      je WFN_Done        ;  Yes
  544.  
  545.     inc Pack.NumRtr        ; Call every noise character a retry
  546.     call Show_retries    ; Display it
  547.     jmp WFN_Loop
  548.  
  549. WFN_Done:
  550.     clc            ; Found a NAK, clear the error flag
  551.     ret            ; Go home happy
  552.  
  553. Wait_for_NAK ENDP
  554.  
  555.  
  556. Wait_for_ACK PROC
  557.  
  558.     mov Abort_flag, 0    ; Clear abort flag
  559.     mov ah, 2Ch        ; Code to Get Time
  560.     int Dos            ; Get it
  561.  
  562.     inc cl            ; Bump the minutes
  563.     cmp cl, 59        ; Too many?
  564.      jbe WFA_doit        ;  No
  565.  
  566.     sub cl, 60        ; Pull down the minutes
  567.     inc ch            ; Bump the hours
  568.  
  569. WFA_doit:
  570.     mov HrMn, cx        ; Save hours and minutes
  571.     mov ScHn, dx        ; Save seconds and hundredths
  572.  
  573. WFA_Loop:
  574.     cmp Count, 0        ; Any characters to read?
  575.      jz WFA_No_char        ;  None
  576.  
  577.     call PrtChr        ; Pick up the character
  578.     cmp al, ACK        ; Did we get an ACK?
  579.      jne WFA_Not_ACK    ;  No
  580.  
  581.     clc            ; Clear the error flag
  582.     ret            ; Go home happy
  583.  
  584. WFA_Not_ACK:
  585.     cmp al, ASCII_NAK    ; Did we get a NAK?
  586.      jne WFA_Not_NAK    ;  Yes
  587.  
  588.     stc            ; Flag the error
  589.     ret            ; Go home
  590.  
  591. WFA_Not_NAK:
  592.     inc Pack.NumRtr        ; Call every noise character a retry
  593.     call Show_retries    ; Display it
  594.     jmp WFA_Loop
  595.  
  596. WFA_No_char:
  597.     mov ah, DConIO        ; Code for direct console input w/o echo
  598.     mov dl, 0FFh        ; Want input mode
  599.     int Dos            ; Get a char if any is there
  600.      jz WFA_No_keyboard    ;  User hasn't typed anything
  601.  
  602.     cmp al, 3        ; User type ^C?
  603.      jne WFA_Not_Ctrl_C    ;  No
  604.  
  605.     mov Abort_flag, 0FFh    ; Flag the abort
  606.     jmp Say_Aborted        ; Standard exit message for ^C
  607.  
  608. WFA_Not_Ctrl_C:
  609.     or al, al        ; Zero?
  610.      jne WFA_Beep        ;  No
  611.  
  612.     int Dos            ; Eat the second part of the funny char
  613.  
  614. WFA_Beep:
  615.     call Beep        ; User hit wrong key, make a noise
  616.  
  617. WFA_No_keyboard:
  618.     call Carry_if_expired    ; See if time has hit yet
  619.      jnc WFA_Loop        ;  Not yet
  620.  
  621.     ret            ; Return with carry set
  622.  
  623. Wait_for_ACK ENDP
  624.  
  625.  
  626. ; Routine to set the Carry Flag if the SLEEP timer has expired, clear it if not
  627.  
  628. Carry_if_expired PROC
  629.  
  630.     mov ah, 2Ch        ; Code to Get Time
  631.     int Dos            ; Get it
  632.  
  633.     cmp cx, HrMn        ; Is the hour/minute too early?
  634.      jb CIE_Not_expired    ;  Yes
  635.      ja CIE_Expired        ;  NO!
  636.  
  637.                 ;  Maybe ...
  638.  
  639.     cmp dx, ScHn        ; How about the seconds?
  640.      jb CIE_Not_expired    ;  Too early
  641.  
  642. CIE_Expired:
  643.     stc            ; Set the carry flag
  644.     ret            ; Return
  645.  
  646. CIE_Not_expired:
  647.     clc            ; Clear the carry flag
  648.     ret            ; Return
  649.  
  650. Carry_if_expired ENDP
  651.  
  652.  
  653.     PUBLIC Receive_a_packet
  654.  
  655. ; Receive_a_packet -- Routine to receive and disassemble an XMODEM data packet
  656.  
  657. Receive_a_packet PROC
  658.  
  659.     mov Timeout, 10        ; Start with a ten second timeout
  660.     call Get_char        ; Get a char or timeout
  661.      jc RAP_empty        ;  Timeout
  662.     cmp al, SOH        ; Proper start?
  663.      je RAP_1        ;  Yes
  664.     cmp al, EOT        ; EOT?
  665.      jne RAP_err        ;  No, error
  666.  
  667.     mov EOT_flag, 1        ; Turn on this flag
  668.     jmp SHORT RAP_OK    ; Acknowledge it like a packet
  669.  
  670. RAP_1:    mov Timeout, 1        ; Switch to a quicker timeout
  671.     call Get_char        ; Get a char or timeout, 1 second
  672.      jc RAP_empty        ;  Timeout
  673.     cmp al, BYTE PTR Pack.PktNum ; Right packet number?
  674.      jne RAP_err
  675.  
  676.     call Get_char        ; Get a char or timeout
  677.      jc RAP_empty        ;  Timeout
  678.     not al            ; Flip the bits
  679.     cmp al, BYTE PTR Pack.PktNum ; Still look right?
  680.      jne RAP_err
  681.  
  682.     mov cx, 128        ; Number of chars to get
  683.     mov di, Buffer_ptr    ; Pick up current ptr
  684.     mov Tally, 0        ; Clear counter
  685.  
  686. RAP_Loop:
  687.     call Get_char        ; Get a char or timeout
  688.      jc RAP_empty        ;  Timeout
  689.  
  690.     stosb            ; Lay down the byte
  691.     sub ah, ah        ; Clear high half
  692.     add Tally, ax        ; Add in the new character
  693.     loop RAP_Loop        ; Do 128 characters
  694.  
  695.     call Get_char        ; Get a char or timeout
  696.      jc RAP_empty        ;  Timeout
  697.     cmp al, BYTE PTR Tally    ; Does the checksum match?
  698.      jne RAP_err        ;  No good
  699.  
  700. RAP_OK:    mov ah, ACK        ; Code to ACK a good packet
  701.     call OutChr        ; Send it out
  702.      nop
  703.      nop
  704.      nop
  705.  
  706.     clc            ; No errors, right block number and everything
  707.     ret            ; Go home
  708.  
  709. RAP_err:
  710.     mov cx, 130        ; Max chars to tolerate in a row
  711.  
  712. RAP_err_2:
  713.     call Get_char        ; Try for another char
  714.      jc RAP_empty        ;  Line is idle
  715.  
  716.     loop RAP_err_2        ; Eat another char
  717.  
  718. RAP_empty:
  719.     mov ah, ASCII_NAK    ; That nasty character
  720.     call OutChr        ; Send it
  721.      nop
  722.      nop
  723.      nop
  724.  
  725.     stc            ; Flag an error
  726.     ret            ; Go home
  727.  
  728. Receive_a_packet ENDP
  729.  
  730.  
  731. ; Send_a_packet -- Routine to assemble and send an XMODEM data packet
  732.  
  733. Send_a_packet PROC
  734.  
  735.     call ClrBuf        ; Flush any chars already received
  736.  
  737.     mov ah, SOH        ; Start each packet with SOH
  738.     call OutChr        ; Send it along
  739.      nop
  740.      nop
  741.      nop
  742.  
  743.     mov ah, BYTE PTR Pack.PktNum ; Copy packet number to ah
  744.     call OutChr        ; Send it along
  745.      nop
  746.      nop
  747.      nop
  748.  
  749.     mov ah, 255        ; Funny packet number encoding
  750.     sub ah, BYTE PTR Pack.PktNum ; One's complement
  751.     call OutChr        ; It too
  752.      nop
  753.      nop
  754.      nop
  755.  
  756.     mov cx, 128        ; Number of chars to send
  757.     mov si, Buffer_ptr    ; Pick up current ptr
  758.     mov Tally, 0        ; Clear counter
  759.  
  760. SAP_Loop:
  761.     lodsb            ; Pick up the byte
  762.     sub ah, ah        ; Clear high half
  763.     add Tally, ax        ; Add in the new character
  764.     mov ah, al        ; Copy char to ah
  765.     call OutChr        ; Send it out
  766.      nop
  767.      nop
  768.      nop
  769.  
  770.     loop SAP_Loop        ; Do 128 characters
  771.  
  772.     mov ah, BYTE PTR Tally    ; Use low order half of total as checksum
  773.     call OutChr        ; Send the checksum (remainder)
  774.      nop
  775.      nop
  776.      nop
  777.  
  778.     ret            ; Go home
  779.  
  780. Send_a_packet ENDP
  781.  
  782.  
  783. Get_char PROC
  784.  
  785.     push cx            ; Save cx reg
  786.     mov Abort_flag, 0    ; Clear abort flag
  787.     mov ah, 2Ch        ; Code to Get Time
  788.     int Dos            ; Get it
  789.  
  790.     add dh, Timeout        ; Add in the timeout time
  791.     cmp dh, 59        ; Too many?
  792.      jle GCH_doit
  793.  
  794.     sub dh, 60        ; Pull down the seconds
  795.     inc cl            ; Bump the minutes
  796.  
  797.     cmp cl, 59        ; Too many?
  798.      jle GCH_doit        ;  No
  799.  
  800.     sub cl, 60        ; Pull down the minutes
  801.     inc ch            ; Bump the hours
  802.  
  803. GCH_doit:
  804.     mov HrMn, cx        ; Save hours and minutes
  805.     mov ScHn, dx        ; Save seconds and hundredths
  806.  
  807. GCH_Loop:
  808.     cmp Count, 0        ; Any characters to read?
  809.      jnz GCH_Got_char    ;  Found one
  810.  
  811.     mov dl, 0FFh        ; Want input mode
  812.     mov ah, DConIO        ; Code for direct console input w/o echo
  813.     int Dos            ; Get a char if any is there
  814.      jz GCH_No_keyboard    ;  User hasn't typed anything
  815.  
  816.     cmp al, 3        ; User type ^C?
  817.      jne GCH_Not_Ctrl_C    ;  No
  818.  
  819.     mov Abort_flag, 0FFh    ; Flag the abort
  820.     call Say_Aborted    ; Standard exit message for ^C
  821.  
  822.     jmp SHORT GCH_done    ; Done here
  823.  
  824. GCH_Not_Ctrl_C:
  825.     or al, al        ; Zero?
  826.      jne GCH_Beep        ;  No
  827.  
  828.     int Dos            ; Eat the second part of the funny char
  829.  
  830. GCH_Beep:
  831.     call Beep        ; User hit wrong key, make a noise
  832.  
  833. GCH_No_keyboard:
  834.     call Carry_if_expired    ; See if time has hit yet
  835.      jnc GCH_loop        ;  Not yet
  836.  
  837.     jmp SHORT GCH_done    ; Timeout
  838.  
  839. GCH_Got_char:
  840.     call PrtChr        ; Pick up the character
  841.     clc            ; Got a character, clear error flag
  842.  
  843. GCH_done:
  844.     pop cx            ; Restore cx reg
  845.     ret            ; Go home happy
  846.  
  847. Get_char ENDP
  848.  
  849.  
  850. ; Jumping to this location is like retskp.  It assumes the instruction
  851. ;   after the call is a jmp addr
  852.  
  853. RSKP    PROC    NEAR
  854.     pop bp
  855.     add bp,3
  856.     push bp
  857. ;    ret
  858. RSKP    ENDP
  859.  
  860. ; Jumping here is the same as a ret
  861.  
  862. R    PROC    NEAR
  863.     ret
  864. R    ENDP
  865.  
  866. Code    ENDS
  867.  
  868.     END
  869. 
  870.